#include "Llamadas.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <time.h>

#define SHM_PERMISOS 0666
#define SHM_KEY_CACHE 107
#define SHM_KEY_STRUCT 108


/* para matarme mas facil usar: killall -9 copiar (en casa, no en el CC)
para verme: ps -lu alex | grep copiar */

/* ejemplo de struct file si se ejecutan 3 copiar en paralelo:
[i=1060917], perm=0, io=0], [i=1057972], perm=3, io=0], 
[i=1060917], perm=0, io=0], [i=1059645], perm=3, io=0], 
[i=1060917], perm=0, io=0], [i=1059647], perm=3, io=0], */

BufferCache * cache; //ambas son para el sistema (mem compartida)
StructFile * structFile;

TDFU tdfu; //para este proceso


void my_sigint(int n, siginfo_t *info, void *p) {  //libera todos sus buffers
   printf("\nCopiar pid = %d signal SIGINT\n", getpid());
   int semCache = semAt(SEM_ID_CACHE); //coge semaforo (mem compartida)
   semWait(semCache);

   for (int i = 0; i < MAX_BUFFERS; i++) //recorre toda la bufferCache
      if (cache->bufs[i].pid == getpid()) 
         brelse(i);

   printf("\nCopiar pid = %d ADIOS\n", getpid());
}

void captura_sigint() { //intercepta la senal SIGINT
   struct sigaction act;
   act.sa_flags = SA_SIGINFO; //tres argumentos -> configurar sa_sigaction
   act.sa_sigaction = my_sigint; //(void *)

   if (sigaction(SIGINT, &act, (struct sigaction *) NULL)) { //intercepta señal, arg3: null: accion anterior no se guarda
      printf("Sigaction dio error = %d", errno);
      exit(0);
   }
}


int main(int argc, char *argv[]) {
   //argumentos
   if ((argc < 3) || (argc > 4)) {
      printf("Introduzca: fichero_origen fichero_destino [numBytes]\n");
      exit(0);
   }

   int nread;
   if (argc == 3) //no se especifico numBytes
      nread = TAM_BLOQUE;
   else
      nread = atoi(argv[3]); //numero de bytes a leer

   if (nread <= 0) {
      printf("El argumento numBytes debe ser mayor de 0\n");
      exit(0);
   }

   //************************ coge mem compartida del demonio *********************************
   //BufferCache
   int idcache = shmget(SHM_KEY_CACHE, sizeof(BufferCache), SHM_PERMISOS); //crea memoria compartida
   if (idcache < 0) {
      fprintf(stderr, "cache shmget failed: %s\n", strerror (errno));
      exit(1);
   }
  
   cache = (BufferCache *) shmat(idcache, (char *) 0, 0); //dato apunta a memoria
   if (cache < (BufferCache *) 0) {
      fprintf (stderr, "cache shmat failed: %s\n", strerror(errno));
      exit(1);
   }  
   

   //Struct File
   int idstruct = shmget(SHM_KEY_STRUCT, sizeof(StructFile), SHM_PERMISOS); //crea memoria compartida
   if (idstruct < 0) {
      fprintf(stderr, "struct file shmget failed: %s\n", strerror (errno));
      exit(1);
   }
  
   structFile = (StructFile *) shmat(idstruct, (char *) 0, 0); //dato apunta a memoria
   if (structFile < (StructFile *) 0) {
      fprintf (stderr, "struct file shmat failed: %s\n", strerror(errno));
      exit(1);
   }

   //************************** Inicializaciones necesarias ***************************
   //captura_sigint();
   captura_usr1_usr2(); //captura senales SIGUSR1 Y SIGUSR2
   tdfu_init();


   //***************** "codigo de usuario" ********************************************
   printf("SOY PID = %d \n", getpid());
   check_corruption("empieza copiar\n");

   int fd1 = abrir(argv[1], O_READ);
   int fd2 = abrir(argv[2], O_CREAR);

   if ((fd1 == NIL) || (fd2 == NIL)) {
      printf("No se pudo abrir algún fichero");
      exit(0);
   }

   //tdfu_print();
   //while(1); //para ver structFile

   printf("Copiando con tamaño = %d ...\n", nread);
   //printf("fd1=%d, fd2=%d \n", fd1, fd2);
   int nwrite = nread; //numero de bytes a escribir. se inicializa a cualquier cosa diferente a FINFICH (0)
   char * buf = new char [nread]; //este new no hace falta, es para que no salga warning xDD

   int nwriten;
   while (nwrite > 0) { //!= FINFICH
      nwrite = leer(fd1, buf, nread);
      //printf("Copiar pid = %d. bytes leidos=%d, buf=%s\n", getpid(), nwrite, buf);
      nwriten = escribir(fd2, buf, nwrite);
      //nwriten = write(fd2, buf, nwrite);
      //printf("Copiar pid = %d. bytes escritos=%d\n", getpid(), nwriten);
   }

   cerrar(fd1);
   cerrar(fd2);
   printf("\nCopiar pid = %d ADIOS\n", getpid());
}

